#import "KxOAuthEngine.h"
#import "OAConsumer.h"
#import "OAMutableURLRequest.h"
#import "OADataFetcher.h"


@interface KxOAuthEngine (private)

- (void) requestURL:(NSURL *) url token:(OAToken *)token onSuccess:(SEL)success onFail:(SEL)fail;
- (void) outhTicketFailed: (OAServiceTicket *) ticket data: (NSData *) data;

- (void) setRequestToken: (OAServiceTicket *) ticket withData: (NSData *) data;
- (void) setAccessToken: (OAServiceTicket *) ticket withData: (NSData *) data;

- (NSString *) extractUsernameFromHTTPBody:(NSString *)body;

- (NSString *)_queryStringWithBase:(NSString *)base parameters:(NSDictionary *)params prefixed:(BOOL)prefixed;

@end

static KxOAuthEngine * _currentOAuthEngine;

@implementation KxOAuthEngine

@synthesize pin = _pin, requestTokenURL = _requestTokenURL, accessTokenURL = _accessTokenURL, authorizeURL = _authorizeURL;
@synthesize consumerSecret = _consumerSecret, consumerKey = _consumerKey;
@synthesize username = _username;
@synthesize consumer = _consumer;
@synthesize requestToken = _requestToken;
@synthesize accessToken = _accessToken;

- (void) dealloc {
	self.pin = nil;
	self.authorizeURL = nil;
	self.requestTokenURL = nil;
	self.accessTokenURL = nil;
	
	[_username release];
	[_accessToken release];
	[_requestToken release];
	[_consumer release];
	[super dealloc];
}

+ (KxOAuthEngine *) OAuthEngineWithDelegate: (NSObject *) delegate {
    return [[[KxOAuthEngine alloc] initOAuthWithDelegate: delegate andScope:@""] autorelease];
}


+ (KxOAuthEngine *) currentOAuthEngine {
	return _currentOAuthEngine;
}


+ (void)setCurrentOAuthEngine:(KxOAuthEngine *)_engine{
	if (_currentOAuthEngine != _engine) {
		[_currentOAuthEngine release];
		_currentOAuthEngine = [_engine retain];
	}
}


- (KxOAuthEngine *) initOAuthWithDelegate: (NSObject *) delegate andScope:(NSString *)scope {
    self = (id) [super init];
    if (self != nil) {
		_delegate = delegate;//liufeng for url
        NSString* strURLString = @"http://api.kaixin001.com/oauth/request_token";
        if([scope length] > 0)
        {
            strURLString = [NSString stringWithFormat:@"%@?scope=%@", strURLString, [scope URLEncodedString]];
        }
		self.requestTokenURL = [NSURL URLWithString: strURLString];
		self.authorizeURL = [NSURL URLWithString: @"http://api.kaixin001.com/oauth/authorize"];
        self.accessTokenURL = [NSURL URLWithString: @"http://api.kaixin001.com/oauth/access_token"];
		
	}
    return self;
}

//=============================================================================================================================
#pragma mark OAuth Code
- (BOOL) OAuthSetup {
	return _consumer != nil;
}

- (OAConsumer *) consumer {
	if (_consumer) 
        return _consumer;
	
	NSAssert(self.consumerKey.length > 0 && self.consumerSecret.length > 0, @"You must first set your Consumer Key and Consumer Secret properties.");
	_consumer = [[OAConsumer alloc] initWithKey: self.consumerKey secret: self.consumerSecret];
	return _consumer;
}

- (OAToken *) requestToken {
	if (_requestToken) {
		return _requestToken;
	}
	return nil;
}

- (OAToken *) accessToken {
	if (_accessToken) {
		return _accessToken;
	}
	return nil;
}

- (void)signOut {
	[self clearAccessToken];
}

- (BOOL) isAuthorized {	
	if (_accessToken.key && _accessToken.secret) return YES;
	
	//first, check for cached creds
	NSString					*accessTokenString = [_delegate respondsToSelector: @selector(kxCachedOAuthDataForUsername:)] ? [(id) _delegate kxCachedOAuthDataForUsername: self.username] : @"";
	
	if (accessTokenString.length) {				
		[_accessToken release];
		_accessToken = [[OAToken alloc] initWithHTTPResponseBody: accessTokenString];
		self.username = [self extractUsernameFromHTTPBody: accessTokenString];
		if (_accessToken.key && _accessToken.secret) 
			return YES;
	}
	
	[_accessToken release];										// no access token found.  create a new empty one
	_accessToken = [[OAToken alloc] initWithKey: nil secret: nil];
	return NO;
}


//This generates a URL request that can be passed to a UIWebView. It will open a page in which the user must enter their Twitter creds to validate
- (NSURLRequest *) authorizeURLRequest {
	if (!_requestToken.key && _requestToken.secret) return nil;	// we need a valid request token to generate the URL

	OAMutableURLRequest			*request = [[[OAMutableURLRequest alloc] initWithURL: self.authorizeURL consumer: nil token: _requestToken realm: nil signatureProvider: nil] autorelease];	
	
	[request setParameters: [NSArray arrayWithObjects: [[[OARequestParameter alloc] initWithName: @"oauth_token" value: _requestToken.key] autorelease], [[[OARequestParameter alloc] initWithName: @"oauth_client" value: @"1"] autorelease], nil]];
    
    //////////////////////////////
    //NSString *path = [NSString stringWithFormat:@"records/add.%@",bin];
//    NSString *path = [NSString stringWithString:@"records/add.bin"];
//    NSMutableDictionary *param = [NSMutableDictionary dictionaryWithCapacity:0];
//    [param setObject:@"test" forKey:@"content"];
//    NSLog(@"网址：%@", );
//    
//    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"record/add.txt"]];
//    
//	
//    [request setParameters: [NSArray arrayWithObjects: [[[OARequestParameter alloc] initWithName: @"oauth_token" value: _requestToken.key] autorelease],nil]];
    //////////////////////////////
    
    
    return request;
}


//A request token is used to eventually generate an access token
- (void) requestRequestToken {
	[self requestURL: self.requestTokenURL token: nil 
		   onSuccess: @selector(setRequestToken:withData:) 
			  onFail: @selector(outhTicketFailed:data:)];
}

//this is what we eventually want
- (void) requestAccessToken {
	[self requestURL: self.accessTokenURL token: _requestToken onSuccess: @selector(setAccessToken:withData:) onFail: @selector(outhTicketFailed:data:)];
}


- (void) clearAccessToken {
	if ([_delegate respondsToSelector: @selector(kxStoreCachedOAuthData:forUsername:)]) 
		[(id) _delegate kxStoreCachedOAuthData: @"" forUsername: self.username];
	[_accessToken release];
	_accessToken = nil;
	[_consumer release];
	_consumer = nil;
	self.pin = nil;
	[_requestToken release];
	_requestToken = nil;
}

- (void) setPin: (NSString *) pin {
	[_pin autorelease];
	_pin = [pin retain];
	
	_accessToken.pin = pin;
	_requestToken.pin = pin;
}

//=============================================================================================================================
#pragma mark Private OAuth methods
- (void) requestURL: (NSURL *) url token: (OAToken *) token onSuccess: (SEL) success onFail: (SEL) fail {
    OAMutableURLRequest				*request = [[[OAMutableURLRequest alloc] initWithURL: url consumer: self.consumer token:token realm:nil signatureProvider: nil] autorelease];
	if (!request) 
		return;
	
	if (self.pin.length) 
		token.pin = self.pin;
    [request setHTTPMethod: @"GET"];//liufeng change to get or we can't get right response
	
    OADataFetcher				*fetcher = [[[OADataFetcher alloc] init] autorelease];	
    [fetcher fetchDataWithRequest: request delegate: self didFinishSelector: success didFailSelector: fail];
}


//
// if the fetch fails this is what will happen
// you'll want to add your own error handling here.
//
- (void) outhTicketFailed: (OAServiceTicket *) ticket data: (NSData *) data {
	if ([_delegate respondsToSelector: @selector(oAuthConnectionFailedWithData:)]) 
		[(id) _delegate oAuthConnectionFailedWithData: data];
}


//
// request token callback
// when twitter sends us a request token this callback will fire
// we can store the request token to be used later for generating
// the authentication URL
//
- (void) setRequestToken: (OAServiceTicket *) ticket withData: (NSData *) data {
	if (!ticket.didSucceed || !data) 
		return;
	
	NSString *dataString = [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease];
	if (!dataString) 
		return;
	
	[_requestToken release];
	_requestToken = [[OAToken alloc] initWithHTTPResponseBody:dataString];
	
	if (self.pin.length) 
		_requestToken.pin = self.pin;
}


//
// access token callback
// when twitter sends us an access token this callback will fire
// we store it in our ivar as well as writing it to the keychain
// 
- (void) setAccessToken: (OAServiceTicket *) ticket withData: (NSData *) data {
	if (!ticket.didSucceed || !data) 
		return;
	
	NSString *dataString = [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease];
	if (!dataString) 
		return;
	
	if (self.pin.length && [dataString rangeOfString: @"oauth_verifier"].location == NSNotFound) 
		dataString = [dataString stringByAppendingFormat: @"&oauth_verifier=%@", self.pin];
	
	NSString				*uid = [self extractUsernameFromHTTPBody:dataString];
	
	/*if (uid.length > 0) {
		self.username = uid;*/
		if ([_delegate respondsToSelector: @selector(kxStoreCachedOAuthData:forUsername:)]) 
			[(id) _delegate kxStoreCachedOAuthData: dataString forUsername: uid];
	//}
	NSLog(@"dataString is :%@", dataString);
	[_accessToken release];
	_accessToken = [[OAToken alloc] initWithHTTPResponseBody:dataString];
}


- (NSString *) extractUsernameFromHTTPBody: (NSString *) body {
	if (!body) return nil;
	
	NSArray					*tuples = [body componentsSeparatedByString: @"&"];
	if (tuples.count < 1) return nil;
	
	for (NSString *tuple in tuples) {
		NSArray *keyValueArray = [tuple componentsSeparatedByString: @"="];
		
		if (keyValueArray.count == 2) {
			NSString				*key = [keyValueArray objectAtIndex: 0];
			NSString				*value = [keyValueArray objectAtIndex: 1];
			
			if ([key isEqualToString:@"screen_name"]) return value;
			if ([key isEqualToString:@"user_id"]) return value;
		}
	}
	
	return nil;
}

@end
